package framework.view.components.scrollbar
{
import flash.display.DisplayObjectContainer;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import framework.view.events.ScrollBarEvent;

[Event(name="scroll_change",
       type="framework.view.events.ScrollBarEvent")]

/**
 * ScrollBar
 * @author jayliang
 *
 */
public class ScrollBar extends Sprite
{
    //==========================================================================
    //  Constructor
    //==========================================================================
    public function ScrollBar()
    {
        super();
        init();
    }
    //==========================================================================
    //  Variables
    //==========================================================================
    protected var thumb:ScrollBarThumb;
    protected var bar:ScrollBarBg;
    protected var target:Sprite;
    protected var targetHeight:Number;
    protected var scrollHeight:Number;
    protected var wheelRect:Shape;
    protected var padding:int;
    //==========================================================================
    //  Properties
    //==========================================================================
    public function get value():Number
    {
        return thumb.value;
    }

    public function set value(v:Number):void
    {
        thumb.value = v;
    }

    public function set thumbHeight(value:Number):void
    {
        if (value > bar.height)
        {
            value = bar.height;
        }
        thumb.height = int(value);
        resetThumbRect();
    }

    public function get thumbHeight():Number
    {
        return thumb.height;
    }

    public function set barHeight(value:Number):void
    {
        bar.height = int(value);
        resetThumbRect();
    }

    public function get barHeight():Number
    {
        return bar.height;
    }

    public function set thumbVisible(value:Boolean):void
    {
        thumb.visible = value;
    }

    public function get thumbVisible():Boolean
    {
        return thumb.visible;
    }
	
	public function get bgSkin():DisplayObjectContainer
	{
		return bar.skin;
	}

    public function set bgSkin(value:DisplayObjectContainer):void
    {
        this.bar.skin = value;
        resetLayout();
    }
	
	public function get thumbSkin():DisplayObjectContainer
	{
		return thumb.skin;
	}

    public function set thumbSkin(value:DisplayObjectContainer):void
    {
        this.thumb.skin = value;
        resetLayout();
    }

    override public function set visible(value:Boolean):void
    {
        super.visible = value;
        if (target)
        {
            if (value)
            {
                target.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
            }
            else
            {
                target.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
            }
        }
    }
    
    public function set thumbPaddingTopAndBottom(value:int):void
    {
        padding = value;
    }
    
    public function get thumbPaddingTopAndBottom():int
    {
        return padding;
    }

    //==========================================================================
    //  Public methods
    //==========================================================================
    public function scrollToBottom():void
    {
        thumb.value = 1;
    }

    public function scrollToTop():void
    {
        thumb.value = 0;
    }

    public function updateWheelTarget(target:Sprite, targetHeight:Number,
                                      scrollHeight:Number):void
    {
        this.target = target;
        this.targetHeight = targetHeight;
        this.scrollHeight = scrollHeight;
        if (!this.target)
        {
            return;
        }
        
        if (!wheelRect)
        {
            wheelRect = new Shape();
            wheelRect.graphics.beginFill(0xFFFFFF, 0);
            wheelRect.graphics.drawRect(0, 0, target.width, targetHeight);
            wheelRect.graphics.endFill();
            this.target.addChildAt(wheelRect, 0);
        }
        else
        {
            wheelRect.width = target.width;
            wheelRect.height = targetHeight;
        }
        
        this.target.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);

        this.thumbHeight = int(this.barHeight *
                           scrollHeight / targetHeight);
    }

    public function dispose():void
    {
        if (target)
        {
            if (wheelRect && target.contains(wheelRect))
            {
                target.removeChild(wheelRect);
                wheelRect = null;
            }
            target.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
            target = null;
        }
        if (thumb)
        {
            thumb.dispose();
            this.removeChild(thumb);
            thumb = null;
        }
        if (bar)
        {
            this.removeChild(bar);
            bar = null;
        }
    }

    //==========================================================================
    //  Protected methods
    //==========================================================================
    protected function init():void
    {
        thumb = new ScrollBarThumb();

        bar = new ScrollBarBg();

        this.addChild(bar);
        this.addChild(thumb);
    }

    protected function resetThumbRect():void
    {
        thumb.scrollArea = new Rectangle(0, padding, 0,
                           bar.height - thumb.height - padding * 2); 
    }
    
    protected function resetLayout():void
    {
        thumb.x = (bar.width - thumb.width) / 2;
        var temp:int = Math.round(thumb.x);
        if (thumb.x - temp != 0)
        {
            bar.width = temp * 2 + thumb.width;
            thumb.x = temp;
        }
    }
    //==========================================================================
    //  Event handlers
    //==========================================================================
    private function mouseWheelHandler(event:MouseEvent):void
    {
        var rect:Rectangle = target.scrollRect;
        if (!rect)
        {
            target.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
            return;
        }

        rect.y -= event.delta * 5;

        var temp:Number = this.targetHeight - this.scrollHeight;
        if (rect.y < 0)
        {
            rect.y = 0;
        }
        else if (rect.y > temp)
        {
            rect.y = temp;
        }
        this.value = rect.y / temp;

        this.dispatchEvent(new ScrollBarEvent(ScrollBarEvent.CHANGE));
    }
}
}